#ifndef LOMTRANSACTIONEVENTSHH
#define LOMTRANSACTIONEVENTSHH
#include "lom-typedefs.hh"
#include "lom-value-factory.hh"
#include "lom-value.hh"

namespace lom
{
    class ILomTransactionEvent
    {
    public:
	virtual ~ILomTransactionEvent(){}
	virtual ETransactionEventType getEventType() const = 0;
	//Only to be called by the transaction system,
	//never by a handler.
	virtual void reset() = 0;
    };
    
    template< ETransactionEventType TEventType >
    class LomTransactionEventImpl : public ILomTransactionEvent
    {
    public:
	virtual ETransactionEventType getEventType() const { return TEventType; }
	virtual void reset(){}
    };
    
    class LomTransactionEventEvent : public LomTransactionEventImpl<ETransactionEventTypeEvent>
    {
	licada::TNameStr name;
	TValueVector args;
	ILomValueFactory* valueFactory;
    public:
	LomTransactionEventEvent() : valueFactory( NULL ){}
	virtual ~LomTransactionEventEvent() {
	    reset();
	}
	
	virtual void reset() {
	    if ( valueFactory )
		do_all( args, boost::bind(&ILomValueFactory::destroy, valueFactory, _1) );
	    args.clear();
	}
	
	void setupEvent( const licada::TNameStr _name, const TValueVector& _args
			 , ILomValueFactory* _valueFactory ) {
	    reset();
	    name = _name;
	    valueFactory = _valueFactory;
	    if ( valueFactory )
	    {
		args.resize( _args.size() );
		std::transform( _args.begin(), _args.end(), args.begin(),
				boost::bind( &LomValue::clone, _1, valueFactory ) );
	    }
	}

	const licada::TNameStr&  getEventName() const { return name; }
	const TValueVector& getEventArgs() const { return args; }
    };
    
    class LomTransactionClassCreatedEvent 
	: public LomTransactionEventImpl<ETransactionEventTypeClassCreated>
    {
	const LomClass* cls;
    public:
	void setupClassCreated( const LomClass* _cls ) { cls = _cls; }
	const LomClass* getClass() const { return cls; }
    };
    
    template< ETransactionEventType EEventType >
    class LomTransactionInstanceEvent 
	: public LomTransactionEventImpl<EEventType>
    {
	THandle handle;
    public:
	void setupInstanceEvent( THandle hdl ) { handle = hdl; }
	THandle getHandle() const { return handle; }
    };

    class LomTransactionInstanceCreatedEvent 
	: public LomTransactionInstanceEvent< ETransactionEventTypeInstanceCreated >
    {
    };
    class LomTransactionInstanceDestroyedEvent 
	: public LomTransactionInstanceEvent<ETransactionEventTypeInstanceDestroyed>
    {
    };
    
    class LomTransactionPropertyEvent 
	: public LomTransactionInstanceEvent<ETransactionEventTypeInstanceProperty>
    {
	licada::uint32 propIndex;
	LomValue* value;
	ILomValueFactory* valueFactory;
    public:
	LomTransactionPropertyEvent() : value( NULL ), valueFactory( NULL ) {}
	virtual ~LomTransactionPropertyEvent() { reset(); }
	
	void setupPropertyEvent( THandle hdl, licada::uint32 _propIndex
				 , const LomValue* _value
				 , ILomValueFactory* _valueFactory ) {
	    setupInstanceEvent( hdl );
	    reset();
	    valueFactory = _valueFactory;
	    propIndex = _propIndex;
	    if( valueFactory )
		value = _value->clone( valueFactory );
	}
	
	virtual void reset() {
	    if ( valueFactory && value)
		valueFactory->destroy( value );
	    value = NULL;
	}
	
	licada::uint32 getPropIndex() const { return propIndex; }
	const LomValue* getValue() const { return value; }
    };
    
    class LomTransactionRootObjectEvent 
	: public LomTransactionEventImpl<ETransactionEventTypeRootObject>
    {
	licada::TNameStr name;
	LomValue* value;
	ILomValueFactory* valueFactory;
    public:
	LomTransactionRootObjectEvent() : valueFactory( NULL ), value(NULL){}
	virtual ~LomTransactionRootObjectEvent() {
	    reset();
	}
	virtual void reset() { if ( valueFactory && value ) valueFactory->destroy( value ); value = NULL; }
	void setupRootObjectEvent( licada::TNameStr _name, const LomValue* _value
				   , ILomValueFactory* _valueFactory ) {
	    reset();
	    name = _name;
	    if ( valueFactory ) valueFactory->destroy( value );
	    valueFactory = _valueFactory;
	    if ( valueFactory ) value = _value->clone( valueFactory );
	}
	const licada::TNameStr& getName() const { return name; }
	const LomValue* getValue() const { return value; }
    };
}
#endif
